package pb

import (
	"context"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/encoding/gurl"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/gclient"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/gogf/gf/v2/util/gutil"
	"go_end/internal/consts"
	"go_end/internal/model/bo"
	"go_end/internal/service"
	"math"
)

type sPb struct {
	User   *bo.PbContextUser `json:"user"`
	Client *gclient.Client
	Header g.MapStrStr
}

func New() *sPb {
	return &sPb{
		User:   &bo.PbContextUser{},
		Client: gclient.New(),
		Header: g.MapStrStr{},
	}
}

func init() {
	service.RegisterPb(New())
}

func (s *sPb) GetPbData(ctx context.Context) string {
	var globConfig = new(bo.GlobConfig)
	config := service.Config().MustGetConfig(ctx, consts.GlobalKey)
	_ = gconv.Scan(config.Value, &globConfig)
	str := `https://{{.host}}/sports-service/sv/compact/events?btg=1&c=&cl=3&d=&ec=&ev=&g=QQ%3D%3D&hle=false&inl=false&l=3&lang=&lg=&lv=&me=0&mk=2&more=false&o=1&ot=2&pa=0&pimo=0%2C1%2C8%2C39%2C2%2C3%2C6%2C7%2C4%2C5&pn=-1&pv=1&sp={{.sportId}}&tm=0&v={{.version}}&locale=zh_CN&_={{.nowTime}}&withCredentials=true`
	url, _ := g.View().ParseContent(gctx.New(), str, g.MapStrAny{
		"host":    getHost(globConfig.PbUrl),
		"version": 0,
		"sportId": 29,
		"nowTime": gtime.Now().Unix(),
	})
	content := s.Client.SetHeaderMap(s.Header).GetContent(ctx, url)
	return content
}

func (s *sPb) GetPbUser(ctx context.Context) *bo.UserInfo {
	var globConfig = new(bo.GlobConfig)
	config := service.Config().MustGetConfig(ctx, consts.GlobalKey)
	_ = gconv.Scan(config.Value, &globConfig)

	str := `https://{{.host}}/member-service/v2/account-balance?locale=zh_CN`
	url, _ := g.View().ParseContent(gctx.New(), str, g.MapStrAny{
		"host": getHost(globConfig.PbUrl),
	})
	content := s.Client.SetHeaderMap(s.Header).GetContent(ctx, url)

	userRes := new(bo.UserInfo)

	json := gjson.New(content)
	userRes.UserId = json.Get("loginId").String()
	userRes.UserName = json.Get("loginId").String()
	userRes.Balance = json.Get("betCredit").String()
	return userRes
}

func (s *sPb) SetUserContext(ctx context.Context, contents string) string {
	return ""
}

func (s *sPb) GetUserContext(ctx context.Context, userInfo *bo.PbContextUser) *bo.PbContextUser {
	return s.User
}

func (s *sPb) SetSession(ctx context.Context, header g.MapStrStr) {
	s.Header = header
}

func (s *sPb) GetSession(ctx context.Context) g.MapStrStr {
	return s.Header
}

func (s *sPb) ParseList(ctx context.Context, contents string) []*bo.GameResp {
	// 解析
	data := gjson.New(contents).GetJsons("l")[0].Array()[2]
	// 转化成list
	array := gjson.New(data).Array()

	var pbArray = make([]*bo.GameResp, 0)

	for i := 0; i < len(array); i++ {
		game := new(bo.GameResp)
		item := gjson.New(array[i]).Array()
		game.GroupId = gconv.String(item[0])
		game.GroupNameCn = gconv.String(item[1])
		game.GroupNameEn = gconv.String(item[4])

		games := gjson.New(item[2]).Array()
		for j := 0; j < len(games); j++ {
			detail := gjson.New(games[j]).Array()
			game.GameId = gconv.String(detail[0])
			game.HomeTeamCn = gconv.String(detail[1])
			game.AwayTeamCn = gconv.String(detail[2])
			game.HomeTeamEn = gconv.String(detail[24])
			game.AwayTeamEn = gconv.String(detail[25])

			game.StartDate = gconv.GTime(detail[4])
			game.StopFlag = gconv.String(detail[17])
			game.IsStop = gstr.Compare("H", gconv.String(detail[17])) == 0
			game.GameTime = ""
			game.GameSection = gconv.String(detail[16])

			gamesIndex9 := gjson.New(detail[9]).Array()
			game.Hs = gconv.Int(gamesIndex9[0])
			game.As = gconv.Int(gamesIndex9[1])

			// 赔率解析
			game.OddsList = parseGameDetail(detail[8])
			pbArray = append(pbArray, game)
		}
	}
	return pbArray
}

func parseGameDetail(oddsMap interface{}) []*bo.GameOddsResp {
	if gutil.IsEmpty(oddsMap) {
		return nil
	}
	array := gjson.New(oddsMap).Map()

	oddsList := make([]*bo.GameOddsResp, 0)
	for i := 0; i <= 1; i++ {
		sectionData := gjson.New(array[gconv.String(i)]).Array()
		section := i //赛节
		if gutil.IsEmpty(sectionData) {
			continue
		}
		// 模式 0-让分，1-大小
		for j := 0; j <= 1; j++ {
			//模式 1-让分，2-大小
			mode := 0
			modeData := gjson.New(sectionData[j]).Array()
			if gutil.IsEmpty(modeData) {
				continue
			}
			if j == 0 {
				mode = 1
			} else if j == 1 {
				mode = 2
			}

			for k := 0; k < len(modeData); k++ {
				m := gjson.New(modeData[k]).Array()
				rowData := getRowData(m, section, mode)
				if rowData == nil {
					continue
				}

				for l := 0; l < len(rowData); l++ {
					oddsList = append(oddsList, rowData[l])
				}
			}
		}
	}
	return oddsList
}

func getRowData(m interface{}, section int, mode int) []*bo.GameOddsResp {
	if gutil.IsEmpty(m) {
		return nil
	}
	item := gjson.New(m).Array()
	var rowData = make([]*bo.GameOddsResp, 0)
	for i := 0; i < 2; i++ {
		// 第1列-选项1,第2列-选项2
		column := getOption(item, section, mode, i)
		rowData = append(rowData, column)
	}
	return rowData
}

func getOption(item []interface{}, section int, mode int, column int) *bo.GameOddsResp {
	var (
		odds  float64
		key   string
		extra string
		desc  string
	)
	res := new(bo.GameOddsResp)
	if mode == 1 {
		// 让分盘
		if column == 0 {
			extra = gconv.String(item[1])
			odds = gconv.Float64(item[3])
			key = "主"
		} else {
			extra = gconv.String(item[0])
			odds = gconv.Float64(item[4])
			key = "客"
		}
		if gconv.Int(extra) > 0 {
			extra = "+" + extra
		}
	} else if mode == 2 {
		//总得分
		extra = gconv.String(item[1])
		if column == 0 {
			odds = gconv.Float64(item[2])
			key = "大"
		} else {
			odds = gconv.Float64(item[3])
			key = "小"
		}
	}

	desc = getExtraDesc(mode, extra)

	res.Odds = odds
	res.Key = key
	res.Extra = extra
	res.Desc = desc
	res.Mode = mode
	res.Section = section

	return res
}

func getExtraDesc(mode int, extra string) string {
	var desc string
	e := gconv.Int(extra)
	if math.Mod(float64(e), 0.5) == 0 {
		desc = extra
	} else {
		abs := math.Abs(float64(e))
		l1 := math.Round(abs)
		l2 := (abs * 2) - l1
		if mode == 1 {
			symbol := "+"
			if e <= 0 {
				symbol = "-"
			}
			desc = symbol + gconv.String(math.Min(l1, l2)/math.Max(l1, l2))
		} else {
			desc = gconv.String(math.Min(l1, l2) / math.Max(l1, l2))
		}
	}
	return desc
}

func getHost(url string) string {
	host, _ := gurl.ParseURL(url, 2)
	return host["host"]
}
